﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;

namespace Foundation.Spell
{
    public class SpellManager
    {
        private readonly SpellChecker _checker;
        public readonly SortedList<string, string[]> Dictionary;
        private readonly Dictionary<string, List<SpellAssotiation>> _cache = new Dictionary<string, List<SpellAssotiation>>();
        private readonly int _dictionarySize;
        private int _connectionAttempts = 1;

        public SpellManager(SpellService service)
        {
            Dictionary = new SortedList<string, string[]>();
            _checker = new SpellChecker(service, Dictionary);
            _checker.NewWordsChecked += words => NewWordsChecked(this, words);
            if (!service.UseDictionaryFile) return;
            var fileName =
                string.IsNullOrEmpty(service.DictionaryFileName)
                    ? service.Name + ".dic.txt"
                    : service.DictionaryFileName;
            fileName = PathProvider.FindFileByName(fileName);
            LoadDictionary(fileName);
            _dictionarySize = Dictionary.Count;
        }

        public event Action<SpellManager, string[]> NewWordsChecked = (manager, words) => { };
        public SpellService WebService { get { return _checker.WebService; } }
        public Regex DefaultWholeWordRegex { get { return SpellChecker.DefaultWholeWordRegex; } }
        public Regex WholeWordRegex { get { return _checker.WholeWordRegex; } }

        public List<SpellAssotiation> Check(string text)
        {
            List<SpellAssotiation> spellErrors;
            if (_cache.TryGetValue(text, out spellErrors)) return spellErrors;

            if (_checker.ExceptionStack.Count >= 7)
            {
                _checker.TryUseWebService = false;
                _checker.ExceptionStack.Clear();
                new Thread(() =>
                    {
                        Thread.Sleep(1000*_connectionAttempts);
                        _checker.TryUseWebService = true;
                        if (_connectionAttempts < 6)
                            _connectionAttempts++;
                    }) {IsBackground = true}.Start();
            }

            string[] newWords;
            spellErrors = _checker.Check(text, out newWords);
            if (!newWords.Any()) _cache.Add(text, spellErrors);
            return spellErrors;
        }

        public List<string> GetRighthWords()
        {
            return Dictionary.Where(p => p.Value == null).Select(p => p.Key).ToList();
        }

        public void SetAssotiations(string word, string[] assotiations)
        {
            lock (Dictionary) _checker.SetAssotiatedWords(word, assotiations);
        }

        public bool TryGetAssotiations(string word, out string[] assotiations)
        {
            return Dictionary.TryGetValue(word, out assotiations);
        }

        public void SaveDictionary(string fileName)
        {
            lock (Dictionary)
            {
                if (_dictionarySize == Dictionary.Count) return;
                var lines =
                    Dictionary.Select(
                        pair =>
                        pair.Key +
                        (pair.Value == null
                             ? string.Empty
                             : ":" + (pair.Value.Any() ? pair.Value.Aggregate((a, b) => a + "," + b) : string.Empty)))
                               .ToList();
                File.WriteAllLines(fileName, lines);
            }
        }

        private void LoadDictionary(string fileName)
        {
            if (File.Exists(fileName))
            {
                var lines = File.ReadAllLines(fileName);
                foreach (var line in lines)
                {
                    var index = line.IndexOf(':');
                    if (index < 1)
                    {
                        _checker.SetAssotiatedWords(line, null);
                        continue;
                    }

                    var word = line.Substring(0, index).Trim();
                    var assotiations = line.Substring(index + 1).Split(',', ':').Where(w => !string.IsNullOrEmpty(w)).ToArray();

                    for (var i = 0; i < assotiations.Length; i++)
                    {
                        assotiations[i] = assotiations[i].Trim();
                    }

                    _checker.SetAssotiatedWords(word, assotiations);
                }
            }
            else File.Create(fileName).Close();
        }
    }
}
